package com.lagou.edu.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lagou.edu.api.UserService;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Setter
@Getter
@RefreshScope
@Slf4j
@RequestMapping  // 让容器扫描到，等同于注册了
public class LoginFilter implements GlobalFilter, Ordered {

    private final static String cookieKey = "lagou_cookie";
    private final static String loginUrl = "/api/user/login";
    private static List<String> whiteList = new ArrayList<>();

    static {
        whiteList.add("/api/code");
        whiteList.add("/api/user/register");
    }

    ObjectMapper objectMapper = new ObjectMapper();
    @Reference
    private UserService userService;

    public Boolean validToken(String token) {
        String email = userService.info(token);
        if (!ObjectUtils.isEmpty(email)) {
            return true;
        }
        return false;
    }

    boolean isContains(String string) {
        return whiteList.stream().anyMatch(string::contains);
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String path = request.getPath().toString();
        if (path.contains(loginUrl)) {
            // 成功返回设置cookie
            return chain.filter(exchange);
        }

        // 路径在白名单
        if (isContains(path)) {
            return chain.filter(exchange);
        }

        if (request.getCookies().isEmpty() || !request.getCookies().containsKey(cookieKey)) {
            return return401Mono(response, HttpStatus.UNAUTHORIZED, "拒绝访问");
        }

        // cookie校验失败
        String value = Objects.requireNonNull(request.getCookies().getFirst(cookieKey)).getValue();
        if (!validToken(value)) {
            return return401Mono(response, HttpStatus.UNAUTHORIZED, "拒绝访问");
        }
        return chain.filter(exchange);
    }

    private Mono<Void> return401Mono(ServerHttpResponse response, HttpStatus status, String... msg) {
        response.setStatusCode(status); // 状态码
        response.getHeaders().set("Content-Type", "application/json;charset=UTF-8");
        String data = "Request be denied!";
        if (!ObjectUtils.isEmpty(msg)) {
            data = msg[0];
        }
        RuntimeException runtimeException = new RuntimeException(data);
        try {
            data = objectMapper.writeValueAsString(runtimeException);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
        return response.writeWith(Mono.just(wrap));
    }

    @Override
    public int getOrder() {
        return 0;
    }

}
